/*  EQEMu:  Everquest Server Emulator
    Copyright (C) 2001-2008  EQEMu Development Team (http://eqemu.org)

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; version 2 of the License.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY except by those people which sell it, which
        are required to give you total support for your newly bought product;
        without even the implied warranty of MERCHANTABILITY or FITNESS FOR
        A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "../common/debug.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <float.h>

#include "../common/files.h"
#include "watermap.h"
#include "../common/MiscFunctions.h"
#ifdef _WINDOWS
#define snprintf        _snprintf
#endif




WaterMap::WaterMap()
: BSP_Root(NULL)
{
}

WaterMap::~WaterMap() {
	safe_delete_array(BSP_Root);
}


WaterRegionType WaterMap::BSPReturnRegionType(sint32 node_number, float y, float x, float z) const
{
	float distance;

	const ZBSP_Node *current_node = &BSP_Root[node_number-1];
	
	// Are we at a leaf
	
	if((current_node->left==0)&&
	   (current_node->right==0))  {
		return (WaterRegionType) current_node->special;
	}
	
	
	// No, so determine which side of the split plane we are on
	//
	
	distance = (x * current_node->normal[0]) +
				   (y * current_node->normal[1]) +
				   (z * current_node->normal[2]) +
				   current_node->splitdistance;
	
	// If we are exactly on the split plane, I don't know what should happen.
	//
	if(distance == 0.0f) {
			return(RegionTypeNormal);
	}
	if(distance >0.0f) {
			if(current_node->left==0) {
					// This shouldn't happen
					return(RegionTypeNormal);
			}
			return BSPReturnRegionType( current_node->left,
							   y, x, z);
	}
	if(current_node->right==0) {
			// This should't happen
			return(RegionTypeNormal);
	}
	
	return BSPReturnRegionType(current_node->right,
					   y, x, z);
}

bool WaterMap::InWater(float y, float x, float z) const {
	if(BSP_Root == NULL) {
		return false;
	}
	return(BSPReturnRegionType(1, y, x, z) == RegionTypeWater);
}

bool WaterMap::InVWater(float y, float x, float z) const {
	if(BSP_Root == NULL) {
		return false;
	}
	return(BSPReturnRegionType(1, y, x, z) == RegionTypeVWater);
}

bool WaterMap::InLava(float y, float x, float z) const {
	if(BSP_Root == NULL) {
		return false;
	}
	return(BSPReturnRegionType(1, y, x, z) == RegionTypeLava);
}

bool WaterMap::InLiquid(float y, float x, float z) const {
	if(BSP_Root == NULL)	//if the water map isn't loaded, this will save ~1 CPU cycle
		return false;
	return (InWater(y, x, z) || InLava(y, x, z));
}

WaterMap* WaterMap::LoadWaterMapfile(const char* in_zonename, const char *directory) {
	FILE *fp;
	char zBuf[64];
	char cWork[256];
	WaterMap* ret = NULL;


	//have to convert to lower because the short names im getting
	//are not all lower anymore, copy since strlwr edits the str.
	strn0cpy(zBuf, in_zonename, 64);

	if(directory == NULL)
		directory = MAP_DIR;
	snprintf(cWork, 250, "%s/%s.wtr", directory, strlwr(zBuf));

	if ((fp = fopen( cWork, "rb" ))) {
		ret = new WaterMap();
		if(ret != NULL) {
			if(ret->loadWaterMap(fp)) {
				printf("Water Map %s loaded.\n", cWork);
			} else {
				safe_delete(ret);
				printf("Water Map %s exists but could not be processed.\n", cWork);
				return NULL;
			}
		} else {
			printf("Water Map %s loading failed.\n", cWork);
		}
		fclose(fp);
	}
	else {
		printf("Water Map %s not found.\n", cWork);
	}
	return ret;
}

bool WaterMap::loadWaterMap(FILE *fp) {
	char EQWMagic[10];
	uint32 BSPTreeSize;
	uint32 EQWVersion;
	
	if(fread(EQWMagic, 10, 1, fp)!=1) {
		printf("Error reading Water region map.\n");
		return(false);
	}
	if(strncmp(EQWMagic,"EQEMUWATER",10)) {
		printf("Bad header in Water  region map.\n");
		return(false);
	}
	if(fread(&EQWVersion, sizeof(EQWVersion), 1, fp)!=1) {
		printf("Error reading Water region map.\n");
		return(false);
	}
	if(EQWVersion!=WATERMAP_VERSION) {
		printf("Incompatible Water region map version.\n");
		return(false);
	}
	
	if(fread(&BSPTreeSize, sizeof(BSPTreeSize), 1, fp)!=1) {
		printf("Error reading Water region map.\n");
		return(false);
	}
	
	BSP_Root = (ZBSP_Node *) new ZBSP_Node[BSPTreeSize];
	
	if(BSP_Root==NULL) {
		printf("Memory allocation failed while reading water map.\n");
		return(false);
	}
	
	if(fread(BSP_Root, sizeof(ZBSP_Node), BSPTreeSize, fp) != BSPTreeSize) {
		printf("Error reading Water region map.\n");
		safe_delete_array(BSP_Root);
		return(false);
	}
	
	printf("Water region map has %d nodes.\n", BSPTreeSize);
	return(true);
}


